package Yasuo

import (
	"Yasuo/conf"
	"Yasuo/iface/icache"
	"Yasuo/iface/istack_opt"
	"Yasuo/stack_opt"
	"container/list"
	"fmt"
	"github.com/xuri/efp"
)

// 操作数栈
// 操作符栈
type Yasuo struct {
	//解析的一条条token。利于跳栈
	AllToken []efp.Token
	// 当前的指针
	CurrentPosi int
	// 需要跳到下一个运行的位置的指针
	NextPosi int
	// 最基本草错数栈
	OPD *list.List
	// 最基本操作符栈
	OPT *list.List
	// 最基本公式栈
	// 比如： op.Status
	OPF *list.List
	// 公式栈的操作数栈
	OPFD *list.List
	// 公式栈的操作符栈
	OPFT *list.List
	// 形参栈，逗号使用的
	ARGS *list.List
	// 临时变量还在那
	VAR map[string]float64
	// 临时变量操作数
	VAROPD *list.List
	// 临时变量操作符
	VAROPT *list.List
	// 逻辑运算符栈
	LOPT *list.List
	// 逻辑操作数站
	LOPD *list.List
}

func NewYasuo(cache icache.ICache) *Yasuo  {
	return &Yasuo{
		AllToken:make([]efp.Token,0),
		CurrentPosi:0,
		NextPosi:0,
		OPD:   list.New(),
		OPT:   list.New(),
		OPF:   list.New(),
		OPFD:  list.New(),
		OPFT:  list.New(),
		ARGS:  list.New(),
		VAR:   make(map[string]float64),
		VAROPD:list.New(),
		VAROPT:list.New(),
		LOPD:list.New(),
		LOPT:list.New(),
	}
}

// 1. 先看缓存器有没有，有就执行对应操作
// 主要计算函数
func (ys *Yasuo) OpCalc(in string) (interface{},error) {
	var (
		itokens interface{}
		tokens []efp.Token
		err error
		inventedOptSty istack_opt.IStackOpt // 自定义解析策略类型
	)

	// 缓存器解析token
	if itokens, err = conf.CacheNow.GetCacheParser(in); err != nil {
		// 没有缓存
		parser := efp.ExcelParser()
		tokens = parser.Parse(in)
	} else {
		// 有缓存
		tokens = itokens.([]efp.Token)
	}

	ys.AllToken = tokens
	//// 添加结束运算
	//ys.AllToken = append(ys.AllToken, efp.Token{
	//	TValue:   "",
	//	TType:    efp.TokenTypeFunction,
	//	TSubType: efp.TokenSubTypeStop,
	//})

	for k, v := range ys.AllToken {
		// 每次判断下一个需要运行的位置
		// todo:
		if ys.NextPosi > len(ys.AllToken) - 1 {
			fmt.Println("???")
			break
		}
		if k != ys.NextPosi {
			continue
		}

		// 根据token获取最先调用的自定义函数，用自定义函数去解析栈
		if inventedOptSty, err =  stack_opt.FactoryStackOpt(v); err != nil {
			fmt.Println("出错就全局崩盘，目前不做差错校验")
			fmt.Println(err)
			return nil,err
		}
		contextStackOpt := stack_opt.NewContextStackOpt(inventedOptSty)
		if contextStackOpt.Strategy.InventedOpt(ys); err != nil {
			return nil,err
		}
	}

	// 最后公共处理
	// 1. 设置缓存
	if conf.CacheNow.SetCacheToken(in, tokens); err != nil {
		return nil,err
	}

	return nil,nil
}